<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>观察者模式完整版</title>
</head>
<body>
<script>
    var Event=(function(){
        var global = this,
            Event,
            _default = 'default';
        Event=function(){
            var _listen,//监听
                _trigger,//触发
                _remove,//移除
                _slice = Array.prototype.slice,
                _shift = Array.prototype.shift,
                _unshift = Array.prototype.unshift,
                namespaceCache = [],//订阅者
                _create,
                find,
                //遍历对象封装的函数
                each=function( ary, fn) {
                    var ret;
                    for(var i = 0, l = ary.length; i < l; i++) {
                        var n = ary[i];
                        ret = fn.call(n, i, n);
                    }
                    return ret;
                };
            //订阅，穿件数组吧？数组名为key，值为fn,创建的感觉是二维数组，二维存储
            //它的函数，他不一定只有一个回调
            _listen = function(key, fn, cache) {
                if(!cache[key]) {
                    cache[key] = [];
                }
                cache[key].push(fn);
            };
            // 移除订阅
            _remove = function(key, cache, fn) {
                if(cache[key]) {
                    if(fn) {
                        for(var i = cache[key].length; i >=0; i++) {
                            if(cache[key][i] === fn) {
                                cache[key].splice(i, 1);
                            }
                        }
                    }else {
                        cache[key] = [];
                    }
                }
            };
            //发布,他也没有传参，参数全是看用户传几个
            _trigger = function() {
                var cache = _shift.call(arguments),
                    key = _shift.call(arguments),
                    args = arguments,
                    _self = this,
                    ret,
                    stack = cache[key];
                if(!stack || !stack.length) {
                    return;
                }
                return each(stack, function() {
                    return this.apply(_self, args);
                });
            };
            //创建命名空间
            _create = function(namespace) {
                var namespace = namespace || _default;
                var cache = {},
                    offlineStack = [],  // 离线事件
                    ret = {
                        listen: function (key, fn, last) {
                            _listen(key, fn, cache);
                            if (offlineStack == null) {
                                return;
                            }
                            if (last === 'last') {
                                offlineStack.length && offlineStack.pop()();
                            } else {
                                each(offlineStack, function () {
                                    this();
                                });
                            }
                            offlineStack = null;
                        },

                        one: function (key, fn, last) {
                            _remove(key, cache);
                            this.listen(key, fn, last);
                        },

                        remove: function(key, fn, last) {
                            _remove(key, cache, fn);
                        },

                        trigger: function() {
                            var fn,
                                args,
                                _self = this;
                            _unshift.call(arguments, cache);
                            args = arguments;
                            fn = function() {
                                return _trigger.apply(_self, args);
                            };
                            if(offlineStack) {
                                return offlineStack.push(fn);
                            }
                            return fn;
                        }
                    };

                return namespace ? (namespaceCache[namespace] ? namespaceCache[namespace] : namespaceCache[namespace] = ret) : ret;
            };
        };
        return {
            create:_create,
            one: function(key, fn, last) {
                var event = this.create();
                event.one(key, fn, last);
            },
            remove: function(key, fn) {
                var event = this.create();
                event.remove(key, fn);
            },
            listen: function(key, fn, last) {
                var event = this.create();
                event.listen(key, fn, last);
            },
            trigger: function() {
                var event = this.create();
                event.trigger.apply(this, arguments);
            }
        };

    })();
    var event1=new Event();
    event1.on("call1",function(data){
        console.log(data);
    });
    event1.listen("call1",function(data){
        console.log(data);
    });
    event1.trigger();
</script>
</body>
</html>